// @HEADER
//*********************************************************************//
//  SiYuan: A numerical PDE solver                                     //
//  Copyright (2022) YUAN Xi                                           //
//  This Software is released under the BSD 2-Clause license detailed  //
//  in the file "LICENSE" in the top-level SiYuan directory            //
//*********************************************************************//
// @HEADER

#ifndef _RYTHMOS_OBSERVER_FACTORY_HPP
#define _RYTHMOS_OBSERVER_FACTORY_HPP

#include "PanzerAdaptersSTK_config.hpp"

#include "Panzer_ResponseLibrary.hpp"
#include "Panzer_Traits.hpp"

#include "Rythmos_CompositeIntegrationObserver.hpp"

// Individual Observers
#include "RythmosObserver_WriteToExodus.hpp"
#include "RythmosObserver_CoordinateUpdate.hpp"

namespace SiYuan {

  class RythmosObserverFactory {

  public:
    RythmosObserverFactory(const Teuchos::RCP<panzer::ResponseLibrary<panzer::Traits> > & stkIOResponseLibrary,
                           const Teuchos::RCP<panzer::WorksetContainer> wkstContainer,
                           bool useCoordinateUpdate)
       : stkIOResponseLibrary_(stkIOResponseLibrary)
       , wkstContainer_(wkstContainer)
       , useCoordinateUpdate_(useCoordinateUpdate) 
    {}

    bool useNOXObserver() const { return false; }
    
    Teuchos::RCP<Rythmos::IntegrationObserverBase<double> >
    buildRythmosObserver(const Teuchos::RCP<panzer_stk::STK_Interface>& mesh,
			 const Teuchos::RCP<const panzer::GlobalIndexer> & dof_manager,
			 const Teuchos::RCP<const panzer::LinearObjFactory<panzer::Traits> >& lof) const
    {
      // all done?
      if(!useCoordinateUpdate_) {
        Teuchos::RCP<RythmosObserver_WriteToExodus> exodus_observer 
            = Teuchos::rcp(new RythmosObserver_WriteToExodus(mesh,dof_manager,lof,stkIOResponseLibrary_));

        return exodus_observer;
      }

      // note: Composite observer loops in the order added
      Teuchos::RCP<Rythmos::CompositeIntegrationObserver<double> > composite_observer =
        Rythmos::createCompositeIntegrationObserver<double>();

      {
        Teuchos::RCP<RythmosObserver_WriteToExodus> observer 
            = Teuchos::rcp(new RythmosObserver_WriteToExodus(mesh,dof_manager,lof,stkIOResponseLibrary_));
        composite_observer->addObserver(observer);
      }

      {
        Teuchos::RCP<RythmosObserver_CoordinateUpdate> observer 
            = Teuchos::rcp(new RythmosObserver_CoordinateUpdate(wkstContainer_));
        composite_observer->addObserver(observer);
      }

      return composite_observer;
    }

  private:
    //! Store STK IO response library...be careful, it will be modified externally
    Teuchos::RCP<panzer::ResponseLibrary<panzer::Traits> > stkIOResponseLibrary_;

    Teuchos::RCP<panzer::WorksetContainer> wkstContainer_;

    //! Use the coordinate update observer?
    bool useCoordinateUpdate_;
  };

}

#endif
